/*
pub enum List {
    Empty,
    Elem(i32, Box<List>)
}
*/

use std::mem;

pub struct List {
    // 不能是pub，否则也会报错。
    head: Link,
}

impl List {
    pub fn new() -> Self {
        List { head: Link::Empty }
    }

    pub fn push(&mut self, elem: i32) {
		let new_node = Box::new(Node {
			elem: elem,
			next: mem::replace(&mut self.head, Link::Empty),
		});

		self.head = Link::More(new_node);
    }

    pub fn pop(&mut self) -> Option<i32> {
		match mem::replace(&mut self.head, Link::Empty) {
			Link::Empty => None,
			Link::More(node) => {
				self.head = node.next;
				Some(node.elem)
			}
		}
    }

    pub fn dump(&self) -> usize {
        let mut start = &self.head;
        let mut count = 0_usize;

        loop {
            match start {
                Link::Empty => {
                    println!("ends");
                    break;
                },
                Link::More(n) => {
                    count += 1;
                    println!("result is: {}", n.elem);
                    start = &n.next;
                }
            }
        }
        count
    }
}

struct Node {
    elem: i32,
    next: Link,
}

enum Link{
    Empty,
    More(Box<Node>),
}

impl Drop for List {
    fn drop(&mut self) {
        // 让引用减1.
        let mut cur_link = mem::replace(&mut self.head, Link::Empty);
        while let Link::More(mut boxed_node) = cur_link {
            cur_link = mem::replace(&mut boxed_node.next, Link::Empty);
        }
    }
}

#[test]
fn test_link() {
    let mut l = List::new();
    l.push(5_i32);
    l.push(8_i32);
	assert_eq!(l.pop(), Some(8));
	assert_eq!(l.pop(), Some(5));
	assert_eq!(l.pop(), None);

}
